home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d8 / pdriver5.arc / NE1000.ASM < prev    next >
Assembly Source File  |  1989-12-17  |  25KB  |  989 lines

  1. ; Packet driver for Novell's NE1000 
  2. ; Written by:
  3. ;    Eric Henderson
  4. ;    Brigham Young University
  5. ;    
  6. ; Based on the "generic" packet driver by Russell Nelson with help
  7. ; from the western digital pd by Russell Nelson.
  8. ; 80[123]86 processor support lifted from 3com driver by permission
  9. ;    from Russell Nelson
  10. ;
  11. ;   Portions (C) Copyright 1989 BYU
  12.  
  13. version    equ    2
  14.  
  15.     include    defs.asm
  16.  
  17. code    segment    byte public
  18.     assume    cs:code, ds:code
  19.  
  20. ;*****************************************************************************
  21. ;
  22. ;    NE1000 controller board offsets
  23. ;    IO port definition (BASE in io_addr)
  24. ;*****************************************************************************
  25. ADDROM  EQU    10h            ; LAN Address ROM
  26. RACK    EQU    10h            ; NE1000 Port Window (?)
  27. NERESET EQU    1fh            ; Issue a read for reset
  28. ; 8390 LAN Controller (page0) register offset for read and write 
  29. CMDR    EQU    00h            ; command register for read & write
  30. CLDA0    EQU    01h            ; current local dma addr 0 for read
  31. PSTART    EQU    01h            ; page start register for write
  32. CLDA1    EQU    02h            ; current local dma addr 1 for read
  33. PSTOP    EQU    02h            ; page stop register for write
  34. BNRY    EQU    03h            ; boundary reg for rd and wr
  35. TSR    EQU    04h            ; tx status reg for rd
  36. TPSR    EQU    04h            ; tx start page start reg for wr    
  37. NCR    EQU    05h            ; number of collision reg for rd
  38. TBCR0    EQU    05h            ; tx byte count 0 reg for wr
  39. FIFO    EQU    06h            ; FIFO for rd
  40. TBCR1    EQU    06h            ; tx byte count 1 reg for wr
  41. ISR    EQU    07h            ; interrupt status reg for rd and wr
  42. CRDA0    EQU    08h            ; current remote dma address 0 for rd
  43. RSAR0    EQU    08h            ; remote start address reg 0  for wr
  44. CRDA1    EQU    09h            ; current remote dma address 1 for rd
  45. RSAR1    EQU    09h            ; remote start address reg 1 for wr
  46. RBCR0    EQU    0Ah            ; remote byte count reg 0 for wr
  47. RBCR1    EQU    0Bh            ; remote byte count reg 1 for wr
  48. RSR    EQU    0Ch            ; rx status reg for rd
  49. RCRWD    EQU    0Ch            ; rx configuration reg for wr
  50. CNTR0    EQU    0Dh            ; tally cnt 0 for frm alg err for rd
  51. TCR    EQU    0Dh            ; tx configuration reg for wr
  52. CNTR1    EQU    0Eh            ; tally cnt 1 for crc err for rd
  53. DCR    EQU    0Eh            ; data configuration reg for wr
  54. CNTR2    EQU    0Fh            ; tally cnt 2 for missed pkt for rd
  55. IMR    EQU    0Fh            ; interrupt mask reg for wr
  56. ; 8390 LAN Controller (page1) register offset for read and write 
  57. PAR0    EQU    01h             ; physical addr reg 0 for rd and wr
  58. PAR1    EQU    02h             ; physical addr reg 1 for rd and wr
  59. PAR2    EQU    03h             ; physical addr reg 2 for rd and wr
  60. PAR3    EQU    04h             ; physical addr reg 3 for rd and wr
  61. PAR4    EQU    05h             ; physical addr reg 4 for rd and wr
  62. PAR5    EQU    06h             ; physical addr reg 5 for rd and wr
  63. CURR    EQU    07h            ; current page reg for rd and wr
  64. MAR0    EQU    08h            ; multicast addr reg 0 fro rd and WR
  65. MAR1    EQU    09h            ; multicast addr reg 1 fro rd and WR
  66. MAR2    EQU    0Ah            ; multicast addr reg 2 fro rd and WR
  67. MAR3    EQU    0Bh            ; multicast addr reg 3 fro rd and WR
  68. MAR4    EQU    0Ch            ; multicast addr reg 4 fro rd and WR
  69. MAR5    EQU    0Dh            ; multicast addr reg 5 fro rd and WR
  70. MAR6    EQU    0Eh            ; multicast addr reg 6 fro rd and WR
  71. MAR7    EQU    0Fh            ; multicast addr reg 7 fro rd and WR
  72.  
  73. ;***********************************************************************
  74. ;
  75. ;    8003 control register operations
  76. ;***********************************************************************
  77.  
  78. MSK_RESET    EQU    80h            ; reset LAN controller
  79. MSK_ENASH    EQU    40h        ; enable PC access to shared mem
  80. MSK_DECOD    EQU    3Fh         ; ???? memory decode bits, corresponding
  81.                     ; to SA 18-13. SA 19 assumed to be 1
  82. ;***********************************************************************
  83. ;
  84. ;    8390 CMDR MASK
  85. ;***********************************************************************
  86.  
  87. MSK_STP        EQU    01h        ; software reset, take 8390 off line
  88. MSK_STA        EQU    02h        ; activate the 8390 NIC
  89. MSK_TXP        EQU    26h        ; initial txing of a frm  (With DMA)
  90. MSK_RD2        EQU    20h        ; abort remote DMA
  91. MSK_PG0        EQU    00h        ; select register page 0
  92. MSK_PG1        EQU    40h        ; select register page 1
  93. MSK_PG2        EQU    80h        ; select register page 2
  94. MSK_DMA_RD    EQU    0ah        ; start DMA read
  95. MSK_DMA_WR    EQU    12h        ; start DMA write
  96.  
  97. ;***********************************************************************
  98. ;
  99. ;    8390 ISR & IMR MASK
  100. ;***********************************************************************
  101.  
  102. MSK_PRX  EQU    01h        ; rx with no error
  103. MSK_PTX  EQU    02h        ; tx with no error
  104. MSK_RXE  EQU    04h        ; rx with error
  105. MSK_TXE  EQU    08h        ; tx with error
  106. MSK_OVW  EQU    10h        ; overwrite warning
  107. MSK_CNT  EQU    20h        ; MSB of one of the tally counters is set
  108. MSK_RDC  EQU    40h        ; remote dma completed
  109. MSK_RST     EQU    80h        ; reset state indicator
  110. UnmaskByte        equ    1fh
  111. InterruptMask        equ    0fh
  112.  
  113. ;***********************************************************************
  114. ;
  115. ;    8390 DCR MASK
  116. ;***********************************************************************
  117.  
  118. MSK_WTS EQU    01h        ; word transfer mode selection
  119. MSK_BOS    EQU    02h        ; byte order selection
  120. MSK_LAS    EQU    04h        ; long addr selection
  121. MSK_BMS    EQU    08h        ; burst mode selection
  122. MSK_ARM    EQU    10h        ; atuoinitialize remote
  123. MSK_FT00 EQU    00h        ; burst lrngth selection
  124. MSK_FT01 EQU    20h        ; burst lrngth selection
  125. MSK_FT10 EQU    40h        ; burst lrngth selection
  126. MSK_FT11 EQU    60h        ; burst lrngth selection
  127.  
  128. ;***********************************************************************
  129. ;
  130. ;    8390 RCR MASK
  131. ;***********************************************************************
  132.  
  133. MSK_SEP EQU    01h        ; save error pkts
  134. MSK_AR     EQU    02h        ; accept runt pkt
  135. MSK_AB     EQU    04h        ; accept broadcast 
  136. MSK_AM     EQU    08h        ; accept multicast 
  137. MSK_PRO    EQU    10h        ; promiscuous physical
  138.                 ; accept all pkt with physical adr
  139. MSK_MON EQU    20h        ; monitor mode
  140.  
  141. ;***********************************************************************
  142. ;
  143. ;    8390 TCR MASK
  144. ;***********************************************************************
  145.  
  146. MSK_CRC EQU    01h        ; inhibit CRC, do not append crc
  147. MSK_LB01 EQU    06h        ; encoded loopback control
  148. MSK_ATD    EQU    08h        ; auto tx disable
  149. MSK_OFST EQU    10h        ; collision offset enable 
  150.  
  151. ;***********************************************************************
  152. ;
  153. ;    8390 RSR MASK
  154. ;***********************************************************************
  155.  
  156. SMK_PRX  EQU    01h        ; rx without error
  157. SMK_CRC  EQU    02h        ; CRC error
  158. SMK_FAE  EQU    04h        ; frame alignment error
  159. SMK_FO   EQU    08h        ; FIFO overrun
  160. SMK_MPA  EQU    10h        ; missed pkt
  161. SMK_PHY  EQU    20h        ; physical/multicase address
  162. SMK_DIS  EQU    40h        ; receiver disable. set in monitor mode
  163. SMK_DEF     EQU    80h        ; deferring
  164.  
  165. ;***********************************************************************
  166. ;
  167. ;    8390 TSR MASK
  168. ;***********************************************************************
  169.  
  170. SMK_PTX  EQU    01h        ; tx without error
  171. SMK_DFR  EQU    02h        ; non deferred tx
  172. SMK_COL  EQU    04h        ; tx collided
  173. SMK_ABT  EQU    08h        ; tx aboort because of excessive collisions
  174. SMK_CRS  EQU    10h        ; carrier sense lost
  175. SMK_FU   EQU    20h        ; FIFO underrun
  176. SMK_CDH  EQU    40h        ; collision detect heartbeat
  177. SMK_OWC     EQU    80h        ; out of window collision
  178.  
  179. ;***********************************************************************
  180. ;
  181. ;    on board memory constant definition
  182. ;***********************************************************************
  183. ; for rcv buff ring of onboard mem
  184. START_PG EQU    26h                  ; start at page 26
  185. STOP_PG  EQU    40h            ; end at page 40 
  186. ; for tx buff of shr mem
  187. TB_SIZE EQU    1            ; number of tb buff in shr mem
  188. TB_PGNO EQU    6            ; number of pages in one tb buff
  189.  
  190.  
  191.     public    int_no, io_addr
  192. int_no        db    3,0,0,0        ;must be four bytes long for get_number.
  193. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  194. my_eaddr      db    6 dup(?)    ; 6 byte LAN address
  195. m_channel     dw     0        ; micro channel flag    
  196. is_186        db    0        ;=0 if 808[68], =1 if 80[123]86.
  197.  
  198. rd_NE    MACRO    port
  199.     mov    DX, CS:io_addr
  200.     add    DX, port        ; DX contains address of port
  201.     in    AL, DX            ; AL contains data read from port
  202.     ENDM
  203.  
  204. wr_NE    MACRO    port
  205.     mov    DX, CS:io_addr
  206.     add    DX, port        ; DX contains address of port
  207.     out    DX, AL            ; AL contains data to be written to port
  208.     ENDM
  209.  
  210. ReceiveHeaderStructure    struc
  211.    RReceiveStatus    db    ?
  212.    RNextBuffer        db    ?
  213.    RByteCount        dw    ?
  214.  
  215.    RDestinationAddress    db    6 dup(?)
  216.    RSourceAddress    db    6 dup(?)
  217.    RPacketLength    dw    ?
  218.    RChecksum        dw    ?
  219.    RRPacketLength    dw    ?
  220.    RTranControl        db    ?
  221.    RHPacketType        db    ?
  222.    RDestinationNet    db    4 dup(?)
  223.    RDestinationNode    db    6 dup(?)
  224.    RDestinationSocket    dw    ?
  225. ReceiveHeaderStructure    ends
  226.  
  227. ReceiveHeader    ReceiveHeaderStructure    <>
  228.  
  229. BLUEBOOK    equ    1
  230. IEEE8023    equ    11h
  231.     public    driver_class, driver_type, driver_name
  232. driver_class    db    BLUEBOOK, 0    ;from the packet spec
  233. driver_type    dw    0ffffh        ;Wild card matches any type
  234. driver_name    db    'NE1000',0    ;name of the driver.
  235.  
  236.     public    rcv_modes
  237. rcv_modes    dw    4        ;number of receive modes in our table.
  238.         dw    0,0,0,rcv_mode_3
  239.  
  240.     public    send_pkt
  241. send_pkt:
  242. ;enter with ds:si -> packet, cx = packet length.
  243. ;exit with nc if ok, or else cy if error, dh set to error number.
  244.     assume    ds:nothing
  245. ; get txblk length                          
  246.     inc    cx
  247.     and    cl, 0feh
  248.     cmp    CX, RUNT
  249.     jnb    length_ok
  250.     mov    cx, RUNT
  251. length_ok:
  252.     cmp    cx, GIANT
  253.     jbe    length1_ok
  254.     mov    dh, NO_SPACE
  255.     stc    
  256.     jmp    count_out_err
  257. length1_ok:
  258. ;new stuff
  259.     mov    AX, CX
  260.     wr_NE    TBCR0            ; Transmit byte count
  261.     mov    al, ah
  262.     wr_NE    TBCR1
  263.     mov    al, 0
  264.     wr_NE    RSAR0
  265.     mov    al, 20h
  266.     wr_NE    RSAR1
  267.     mov    ax, cx
  268.     wr_NE    RBCR0            ; Remote byte count
  269.     mov    al, ah
  270.     wr_NE    RBCR1
  271.  
  272.  
  273. ; Clear out DMA complete interrupt
  274.     mov    al, MSK_PG0        
  275.     wr_NE    CMDR
  276.     mov    al, 40h
  277.     wr_NE    ISR
  278.  
  279.     mov    al, MSK_DMA_WR
  280.     wr_NE    CMDR
  281.  
  282.     mov    DX, CS:io_addr
  283.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  284.  
  285.     cmp    is_186,0    ; Can we use rep outsb?
  286.     je    out86        ; no - have to do it slowly.
  287.     rep    outsb
  288.     jmp    short ocnteven
  289. out86:
  290.     test    si,1        ; (buf & 1) ?
  291.     jz    obufeven    ; no
  292.     lodsb            ; al = *si++;
  293.     out    dx,al        ; out(dx,al);
  294.     dec    cx        ; cx--;
  295. obufeven:
  296.     mov    di,cx        ; save for later test
  297.     shr    cx,1        ; cx = cnt >> 1; (convert to word count)
  298. ; Do the bulk of the buffer, a word at a time
  299.     jcxz    onobuf        ; if(cx != 0){
  300. xb:    lodsw            ; do { ax = *si++; (si is word pointer)
  301.     out    dx,al        ; out(dx,lowbyte(ax));
  302.     mov    al,ah
  303.     out    dx,al        ; out(dx,hibyte(ax));
  304.     loop    xb        ; } while(--cx != 0); }
  305. ; now check for odd trailing byte
  306. onobuf:    shr    di,1        ; if (di & 1)
  307.     jnc    ocnteven
  308.     lodsb            ;   out(dx,*si++);
  309.     out    dx,al
  310. ocnteven:
  311.     mov    cx, 1000h        ; Prevent infinite loop
  312. WaitForDMAComplete:
  313.     rd_NE    ISR
  314.     test    al, 40h
  315.     jnz    DMAComplete
  316.     loop    WaitForDMAComplete
  317.  
  318. DMAComplete:
  319.     mov    al, MSK_TXP
  320.     wr_NE    CMDR
  321.     clc
  322. exit_now:
  323.     ret
  324.  
  325.  
  326.     public    get_address
  327. get_address:
  328. ;get the address of the interface.
  329. ;enter with es:di -> place to get the address, cx = size of address buffer.
  330. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  331.     assume    ds:code
  332.     cmp cx,    EADDR_LEN    ; Caller wants a reasonable length?
  333.     jb    get_addr_x    ; No, fail.
  334.     mov cx,    EADDR_LEN    ; Yes. Set count for loop
  335.     mov    si, offset cs:my_eaddr
  336.     cld            ; Make sure string mode is right
  337.     rep    movsb
  338.     mov cx,    EADDR_LEN    ; Tell caller how many bytes we fed him
  339.     clc            ; Carry off says success
  340.     ret
  341. get_addr_x:
  342.     stc            ; Tell caller our addr is too big for him
  343.     ret
  344.  
  345.  
  346.     public    set_address
  347. set_address:
  348. ;enter with ds:si -> Ethernet address, CX = length of address.
  349. ;exit with nc if okay, or cy, dh=error if any errors.
  350. ;This proc will set the first CX bytes of the ethernet address, leaving
  351. ; the rest unchanged.
  352.     assume    ds:nothing
  353.  
  354.     cmp    cx, 6
  355.     jbe    set1
  356.     mov    dh, BAD_ADDRESS
  357.     stc
  358.     ret
  359. set1:
  360.     push    es
  361.     push    di
  362.     mov    di, offset my_eaddr
  363.     mov    ax, cs
  364.     mov    es, ax
  365.  
  366.     mov    al, 61h
  367.     wr_NE    CMDR
  368.     mov    DX, CS:io_addr
  369.     add    DX, PAR0        ; DX has address 8390 Phys Address Reg
  370. AddressToChip1:
  371.     lodsb
  372.     out    dx, al
  373.     mov    es:[di], al
  374.     inc    di
  375.     inc    dx
  376.     nop
  377.     nop
  378.     nop    
  379.     nop
  380.     loop    AddressToChip1
  381.     pop    di
  382.     pop    es
  383.  
  384.     mov     al, 21h
  385.     wr_NE     CMDR
  386.     clc
  387.     ret
  388.  
  389.  
  390. rcv_mode_3:
  391. ;receive mode 3 is the only one we support, so we don't have to do anything.
  392.     ret
  393.  
  394.  
  395.     public    set_multicast_list
  396. set_multicast_list:
  397. ;enter with es:di ->list of multicast addresses, cx = number of bytes.
  398. ;return nc if we set all of them, or cy,dh=error if we didn't.
  399.     mov    dh,NO_MULTICAST
  400.     stc
  401.     ret
  402.  
  403.  
  404.     public    get_multicast_list
  405. get_multicast_list:
  406. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  407. ;return cy, NO_ERROR if we don't remember all of the addresses ourselves.
  408. ;return cy, NO_MULTICAST if we don't implement multicast.
  409.     mov    dh,NO_MULTICAST
  410.     stc
  411.     ret
  412.  
  413.  
  414.     public    reset_interface
  415. reset_interface:
  416. ;reset the interface.
  417.     assume    ds:code
  418.     mov    al, MSK_STP + MSK_RD2    
  419.     wr_NE    CMDR
  420.     mov al,    0ffh        ; Clear all pending interrupts
  421.     wr_NE    ISR
  422.     xor al,    al        ; Turn off all enables
  423.     wr_NE    IMR
  424.     rd_NE   NERESET        ; Hard reset NE1000
  425.     wr_NE   NERESET
  426.     ret
  427.  
  428.  
  429. ;called when we want to determine what to do with a received packet.
  430. ;enter with cx = packet length, es:di -> packet type.
  431. ;It returns with es:di = 0 if don't want this type or if no buffer available.    
  432.     extrn    recv_find: near
  433.  
  434. ;called after we have copied the packet into the buffer.
  435. ;enter with ds:si ->the packet, cx = length of the packet.
  436.     extrn    recv_copy: near
  437.  
  438.     extrn    count_in_err: near
  439.     extrn    count_out_err: near
  440.  
  441.  
  442.     public    recv
  443. recv:
  444. ;called from the recv isr.  All registers have been saved, and ds=cs.
  445. ;Actually, not just receive, but all interrupts come here.
  446. ;Upon exit, the interrupt will be acknowledged.
  447.     assume    ds:code
  448.  
  449. ; read irq status register
  450.  
  451. rd_isr:
  452.     rd_NE    ISR            ; read isr into AL
  453.     and    AL, 3Fh            ; check bit0-bit5, if all 1's no irq
  454.     cmp    AL, 0            ; if any irq
  455.     jne    tst_ovw            ; some irq
  456.     ret                ; no more irq, exit
  457.  
  458. ; process OVW    (OVW = 1)       
  459. ;    may report error here
  460. tst_ovw:
  461.     test    AL, MSK_OVW        ; if OVW irq
  462.     jnz    prcs_ov            ; OVW (OVW = 1) 
  463.     jmp    test_rx            ; no OVW (OVW = 0) 
  464.  
  465. ; **************************************************************
  466. ; follow the DP8390 datasheet addendum to handle the buff ring overflow
  467. prcs_ov:
  468. ; 1. issue a STOP mode command
  469.     mov    AL, MSK_STP + MSK_RD2
  470.     wr_NE    CMDR
  471.     jmp    $+2
  472. ; 6. remove one packet from the ring
  473.     rd_NE    BNRY            ; BNRY in AL
  474.     add    AL, 1            ; start page of frm in AL
  475.     cmp    AL, STOP_PG        ; check boundary
  476.         jne    get1
  477.     mov    AL, START_PG        
  478. ; ring not empty
  479. get1:
  480.     mov    BH, AL            ; BX has the rx_frm pointer
  481.  
  482.     mov    al, SIZE ReceiveHeader
  483.     wr_NE    RBCR0
  484.     xor    al, al
  485.     jmp    $+2
  486.     wr_NE    RBCR1
  487.     jmp    $+2
  488.     wr_NE    RSAR0
  489.     mov    al, bh
  490.     wr_NE    RSAR1
  491.     mov    al, MSK_DMA_RD
  492.     wr_NE    CMDR
  493.  
  494.     mov    DX, CS:io_addr
  495.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  496.     mov    di, OFFSET ReceiveHeader
  497.     mov    ax, cs
  498.     mov    es, ax
  499.     mov    cx, SIZE ReceiveHeader
  500.     
  501. Receive1:
  502.     in    al, dx
  503.     stosb
  504.     loop    Receive1
  505.  
  506. SkipReceive1:
  507.     mov    bx, offset ReceiveHeader
  508.     mov    AL, CS:[BX]        ; AL has the status byte
  509.     test    AL, SMK_PRX        ; if rx good
  510.     jz    fd_bnr            ; rx error, drop frm by forward bnry
  511.  
  512. ; good frm, call _rcv_frm
  513.     call     _rcv_frm           
  514.  
  515. fd_bnr:                    ;drop frm by forward BNRY
  516.     mov    al, cs:ReceiveHeader.RNextBuffer    ; al = next pointer 
  517.     sub    AL, 1            ; new BNRY in AL
  518.     cmp    AL, START_PG        ; check boundary
  519.     jae    wrbnr            ; unsigned arithmetic
  520.     mov    AL, STOP_PG        ;
  521.     dec    AL            ;
  522. wrbnr:
  523.     wr_NE    BNRY
  524.     jmp    $+2            ;
  525. ; 2. clear the remote byte count registers (RBCR0,RBCR1)
  526.     xor    AL, AL
  527.     wr_NE    RBCR0
  528.     jmp    $+2            ;
  529.     wr_NE    RBCR1
  530.     jmp    $+2            ;
  531. ; 3. poll the ISR for the RST bit
  532. plisr:
  533.     rd_NE    ISR
  534.     jmp    $+2            ;
  535.     test    AL, MSK_RST
  536.     jz    plisr        ; keep polling until the RST bit set
  537. ; 4. place the NIC in loopback mode (mode 1 or 2) by writing 02 or 04 to TCR
  538.     mov    AL, 02h        ; put it in mode 2 (internal loopback)
  539.     wr_NE    TCR
  540.     jmp    $+2            ;
  541. ; 5. issue start mode command
  542.     mov    AL, MSK_STA + MSK_RD2
  543.     wr_NE    CMDR
  544.     jmp    $+2            ;
  545. ; 7. out from loopback mode by writing 00 to TCR
  546.     xor    AL, AL
  547.     wr_NE    TCR        ; normal operation configuration
  548.     jmp    $+2            ;
  549. ; clear OVW in ISR              
  550.     mov    AL, MSK_OVW 
  551.     wr_NE    ISR            ; clear OVW
  552.     call    count_in_err        ; increment overflow counter
  553.     jmp    rd_isr            ; back to the top
  554.  
  555.  
  556. ; end of the modification 
  557. ; *****************************************************
  558. ;    
  559. ;process PRX and RXE
  560. ;
  561. test_rx:        
  562.     test      AL, MSK_PRX    
  563.     jnz    prcs_rx                 ; PRX = 1
  564.     test     AL, MSK_RXE        
  565.     jnz    prcs_rxe        ; RXE = 1
  566.     jmp    test_tx
  567.  
  568. prcs_rxe:
  569.     call    count_in_err
  570. prcs_rx:
  571.     mov    AL, MSK_PG1 + MSK_RD2    ; read CURR reg
  572.     wr_NE    CMDR
  573.     jmp    $+2
  574.     rd_NE    CURR
  575.     jmp    $+2
  576.     mov    BL, AL            ; CURR in BL 
  577.     mov    AL, MSK_PG0 + MSK_RD2    ; read BNRY reg
  578.     wr_NE  CMDR
  579.     jmp    $+2
  580.     rd_NE    BNRY            ; BNRY in AL
  581.     add    AL, 1            ; start page of frm in AL
  582.     cmp    AL, STOP_PG         ; check boundary
  583.     jne    go_cmp
  584.     mov    AL, START_PG         ;         
  585. go_cmp:
  586.     cmp    AL, BL            
  587.     je    end_rx            ; buff ring empty
  588.  
  589. ; Ring Not Empty
  590.     wr_NE    RSAR1
  591.     jmp    $+2
  592.     xor    al, al
  593.     jmp    $+2
  594.     wr_NE    RBCR1
  595.     jmp    $+2
  596.     wr_NE    RSAR0
  597.     mov    al, SIZE ReceiveHeader
  598.     wr_NE    RBCR0
  599.     mov    al, MSK_DMA_RD
  600.     wr_NE    CMDR
  601.  
  602.     mov    DX, CS:io_addr
  603.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  604.     mov    di, OFFSET ReceiveHeader
  605.     mov    ax, cs
  606.     mov    es, ax
  607.     mov    cx, SIZE ReceiveHeader
  608.  
  609. Receive2:
  610.     in    al, dx
  611.     stosb
  612.     loop    Receive2
  613.  
  614. SkipReceive2:
  615.     mov    bx, offset ReceiveHeader
  616.     mov    AL, CS:[BX]        ; AL has the status byte
  617.     test    AL, SMK_PRX        ; if rx good
  618.     jz    fd_bnry            ; rx error, drop frm by forward bnry
  619.  
  620. ; good frm, call _rcv_frm
  621.        call     _rcv_frm           
  622.  
  623. fd_bnry:                ; drop frm by forward BNRY
  624.     mov    al, CS:ReceiveHeader.RNextBuffer    ; al = next pointer 
  625.     sub    AL, 1            ; new BNRY in AL
  626.     cmp    AL, START_PG        ; check boundary
  627.     jae    wrbnry            ; unsigned arithmetic
  628.     mov    AL, STOP_PG        ;
  629.     dec    AL            ;
  630. wrbnry:
  631.     wr_NE    BNRY
  632.     jmp    prcs_rx     
  633.        
  634. ; clear PRX, RXE, OVW in ISR              
  635. end_rx:
  636.     mov    AL, MSK_OVW + MSK_RXE + MSK_PRX
  637.     wr_NE    ISR            ; clear OVW, RXE, PRX
  638.     jmp    rd_isr            ; back to the top
  639.  
  640. ;process PTX and TXE
  641. test_tx:
  642.     test      AL, MSK_PTX    
  643.     jnz    prc_ptx                 ; PTX = 1
  644.     test     AL, MSK_TXE        
  645.     jnz    prc_txe            ; TXE = 1
  646.     jmp    test_cnt
  647.       
  648.  
  649. ; process tx good, update txok, lostcrs, collsn
  650. prc_ptx:                ; tx good 
  651.     rd_NE    TSR
  652.     test    AL, SMK_CRS        ; is crs set in TSR
  653.     jz    nocrs            ; no               
  654. nocrs:    
  655.     rd_NE    NCR            ; read number of collision in AL
  656.     mov    AL, MSK_PTX
  657.     wr_NE    ISR            ; clear PTX
  658.     jmp    rd_isr
  659.  
  660. ; process tx error, update .txbad .underrun
  661. prc_txe:                ; tx bad
  662.     call    count_out_err    
  663.     rd_NE    TSR
  664.     test    AL, SMK_FU        ; it fu set in TSR
  665.     jz    nofu            ; no               
  666. nofu:                                  
  667.         mov    AL, MSK_TXE
  668.     wr_NE    ISR            ; clear PTX
  669.     jmp    rd_isr
  670.  
  671. ; process counter overflow, update .algerr .crcerr .???(missed pkt)
  672. test_cnt:
  673.     test      AL, MSK_CNT    
  674.     jnz    prc_cnt            ; yes, process cnt
  675.     jmp    rd_isr                 ; no CNT irq, back to the top
  676. ; process CNT            
  677. prc_cnt:
  678.     mov    AL, MSK_CNT
  679.     wr_NE    ISR            ; clear CNT
  680.     jmp    rd_isr            ; back to the top
  681.  
  682. ; End of RECV
  683.  
  684. _rcv_frm:
  685.     
  686. ; read byte count 
  687.     mov     cx, cs:ReceiveHeader.RByteCount    ; Extract size of frame
  688.     cmp    CX, 5dch
  689.     jna    rxlen_ok
  690.     jmp    rcv_ret
  691. rxlen_ok:
  692.     sub    CX, 4            ; 4 control bytes
  693.     mov    AX, cs
  694.     mov    ES, AX
  695.     mov     di, offset cs:ReceiveHeader.RPacketLength
  696.  
  697.     push    cx            ; Save frame size
  698.     push    es
  699.  
  700.     mov ax,    cs            ; Set ds = code
  701.     mov ds,    ax
  702.     assume    ds:code
  703.     call    recv_find        ; See if type and size are wanted
  704.                     ;     CX = packet length
  705.                     ;    ES:DI = packet type
  706.  
  707.     pop    ds            ; RX page pointer in ds now
  708.     assume    ds:nothing
  709.     pop    cx
  710.  
  711.     cld                ; Copies below are forward
  712.     mov ax,    es            ; Did recv_find give us a null pointer?
  713.     or  ax,    di            ; ..
  714.     je    no_buff            ; If null, don't copy the data    
  715. has_buf:  
  716.  
  717. ;Tell DMA to copy the whole packet for us
  718.     mov    ax, 4
  719.     wr_NE    RSAR0        ; Don't copy  4 8390 control bytes
  720.     mov    ax, cx        ; CX has byte count
  721.     wr_NE    RBCR0        ; LSB first
  722.     mov    al, ah
  723.     wr_NE    RBCR1        ; Now MSB
  724.  
  725.     mov    al, MSK_DMA_RD  ; Issue DMA read command
  726.     wr_NE    CMDR
  727.  
  728. ; copy from NE1000 on board memory using the window RACK
  729. ; use IN and stosb to do the copy, IN -> AX -> ES:DI (CX has byte count)                        
  730.  
  731. copynow:
  732.     push    cx        ; We will want the count and pointer
  733.     push    es        ;  to hand to client after copying,
  734.     push    di        ;  so save them at this point
  735.  
  736.     mov    DX, CS:io_addr
  737.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  738.  
  739.     cmp    is_186,0    ; Can we use rep insb?
  740.     je    in86        ; no - have to do it slowly.
  741.     rep    insb
  742.     jmp    short icnteven
  743. in86:
  744. ; If buffer doesn't begin on a word boundary, get the first byte
  745.     test    di,1    ; if(buf & 1){
  746.     jz    ibufeven ;
  747.     in    al,dx    ; al = in(dx);
  748.     stosb        ; *di++ = al
  749.     dec    cx    ; cx--;
  750. ibufeven:
  751.     mov    si,cx    ; size = cx;
  752.     shr    cx,1    ; cx = cnt >> 1; (convert to word count)
  753. ; Do the bulk of the buffer, a word at a time
  754.     jcxz    inobuf    ; if(cx != 0){
  755. rb:    in    al,dx    ; do { al = in(dx);
  756.     mov    ah,al
  757.     in    al,dx    ; ah = in(dx);
  758.     xchg    al,ah
  759.     stosw        ; *si++ = ax; (di is word pointer)
  760.     loop    rb    ; } while(--cx != 0);
  761. ; now check for odd trailing byte
  762. inobuf:    shr    si,1
  763.     jnc    icnteven
  764.     in    al,dx
  765.     stosb        ; *di++ = al
  766. icnteven:
  767.  
  768. call_rc:
  769.     pop    si            ; Recover pointer to destination
  770.     pop    ds            ; Tell client it's his source
  771.     pop    cx            ; And it's this long
  772.     assume    ds:nothing
  773.     call    recv_copy        ; Give it to him
  774.     jmp    short rcv_ret
  775.  
  776. ; no system buff availble to hold rx frm
  777. no_buff:
  778. rcv_ret:
  779.     push    cs        ; Put ds back in code space
  780.     pop    ds        ; ..
  781.     assume    ds:code
  782.     ret
  783.  
  784.  
  785.  
  786.     public    recv_exiting
  787. recv_exiting:
  788. ;called from the recv isr after interrupts have been acknowledged.
  789. ;Only ds and ax have been saved.
  790.     assume    ds:nothing
  791.     ret
  792.  
  793.  
  794. ;any code after this will not be kept after initialization.
  795. end_resident    label    byte
  796.  
  797.  
  798.     public    usage_msg
  799. usage_msg    db    "usage: NE1000 <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
  800.  
  801.     public    copyright_msg
  802. copyright_msg    db    "Packet driver for NE1000, version "
  803.         db    '0'+majver,".",'0'+version,CR,LF
  804.         db    "Portions Copyright 1989, Eric Henderson, BYU",CR,LF,'$'
  805. int_no_name    db    "Interrupt number ",'$'
  806. io_addr_name    db    "I/O port ",'$'
  807. no_board_msg:
  808.     db    "NE1000 apparently not present at this IO address.",CR,LF,'$'
  809. HardwareFailure:
  810.     db    "The NE1000 is not responding.",CR,LF,'$'
  811. using_186_msg    db    "Using 80[123]86 I/O instructions.",CR,LF,'$'
  812.  
  813.     extrn    set_recv_isr: near
  814.  
  815. ;enter with si -> argument string, di -> word to store.
  816. ;if there is no number, don't change the number.
  817.     extrn    get_number: near
  818.  
  819.     public    parse_args
  820. parse_args:
  821.     mov    di,offset int_no
  822.     mov    bx,offset int_no_name
  823.     call    get_number
  824.     mov    di,offset io_addr
  825.     mov    bx,offset io_addr_name
  826.     call    get_number
  827.     ret
  828.  
  829.     extrn    etopen_diagn: byte
  830.  
  831. BoardNotResponding:
  832.     mov    dx, offset HardwareFailure
  833.     mov    etopen_diagn, 35
  834.     jmp    short error_wrt
  835. bad_cksum:
  836. no_memory:
  837.     mov    dx,offset no_board_msg
  838.     mov    etopen_diagn,37
  839. error_wrt:
  840.     mov    ah,9
  841.     int    21h
  842.     stc
  843.     ret
  844.  
  845.     public    etopen
  846. etopen:
  847. ;if all is okay,
  848.  
  849.     ; reset NE1000 board 
  850.     rd_NE    NERESET
  851.     wr_NE    NERESET
  852.     mov    al, 21h
  853.     wr_NE    CMDR
  854.  
  855.     ; Test to see if we're OK
  856.     rd_NE    CMDR
  857.     cmp    al, 21h
  858.     je    WeBeOK
  859.     jmp    BoardNotResponding
  860.  
  861. WeBeOK:
  862.     mov    al, 0
  863.     wr_NE    DCR        
  864.     mov    al, 60h
  865.     wr_NE    TPSR        
  866.     mov    al, 0
  867.     wr_NE    TCR        
  868.     mov    al, 20h
  869.     wr_NE    RCRWD        
  870.     mov    al, 4
  871.     wr_NE    PSTART        
  872.     mov    al, 4
  873.     wr_NE    BNRY        
  874.     mov    al, 0ffh
  875.     wr_NE    PSTOP        
  876.     mov    al, 3ch
  877.     wr_NE    TBCR0        
  878.     mov    al, 0
  879.     wr_NE    TBCR1        
  880.     mov    al, 0ffh
  881.     wr_NE    ISR        
  882.     mov    al, 61h
  883.     wr_NE    CMDR        
  884.     mov    al, 4
  885.     wr_NE    CURR        
  886.     mov    al, 22h
  887.     wr_NE    CMDR        
  888.  
  889.     ; Test to see if we're still OK
  890.     rd_NE    CMDR
  891.     cmp    al, 22h
  892.     je    WeBeStillOK
  893.     jmp    BoardNotResponding
  894.  
  895. WeBeStillOK:
  896.  
  897.     ; set up my_eaddr from addr ROM 
  898.     mov    al, 21h
  899.     wr_NE    CMDR
  900.     mov    al, 6
  901.     wr_NE    RBCR0
  902.     mov    al, 0
  903.     wr_NE    RBCR1
  904.     wr_NE    RSAR0
  905.     wr_NE    RSAR1
  906.     mov    al, MSK_DMA_RD
  907.     wr_NE    CMDR
  908.  
  909.     mov    DX, CS:io_addr
  910.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  911.     mov    di, OFFSET my_eaddr
  912.     mov    ax, cs
  913.     mov    es, ax
  914.     mov    cx, 6
  915. GetEnetAddress:
  916.     in    al, dx
  917.     stosb
  918.     loop    GetEnetAddress
  919.  
  920.     mov    ax, cs
  921.     mov    ds, ax
  922.     mov    si, OFFSET my_eaddr
  923.     mov    cx, 6
  924.     call    set_address
  925.  
  926.     mov     al, 21h
  927.     wr_NE     CMDR
  928.  
  929.     mov    al, START_PG
  930.     jmp    $+2
  931.     wr_NE    PSTART
  932.     jmp    $+2
  933.     wr_NE    BNRY
  934.     mov    al, STOP_PG
  935.     jmp    $+2
  936.     wr_NE    PSTOP
  937.  
  938.     mov    al, 61h
  939.     jmp    $+2
  940.     wr_NE    CMDR
  941.     mov    al, START_PG + 1
  942.     jmp    $+2
  943.     wr_NE    CURR
  944.     mov    al, 21h
  945.     jmp    $+2
  946.     wr_NE    CMDR
  947.  
  948.     mov     al, 48h
  949.     jmp    $+2
  950.     wr_NE    DCR
  951.     mov    al, 0
  952.     jmp    $+2
  953.     wr_NE    TCR
  954.     mov    al, MSK_RXE
  955.     jmp    $+2
  956.     wr_NE    RCRWD
  957.     mov    al, 0ffh
  958.     jmp    $+2
  959.     wr_NE    ISR
  960.     mov    al, UnmaskByte
  961.     jmp    $+2
  962.     wr_NE    InterruptMask
  963.  
  964. ;Determine the processor type.  The 8088 and 8086 will actually shift ax
  965. ;over by 33 bits, while the 80[123]86 use a shift count mod 32.
  966.     mov    cl,33
  967.     mov    ax,0ffffh
  968.     shl    ax,cl
  969.     jz    not_186
  970.     mov    is_186,1
  971.     mov    dx,offset using_186_msg
  972.     mov    ah,9
  973.     int    21h
  974. not_186:
  975.  
  976.     call    set_recv_isr    ; Put ourselves in interrupt chain
  977.     
  978.     mov    al, 22h
  979.     jmp    $+2
  980.     wr_NE    CMDR    
  981.  
  982.     mov    dx,offset end_resident
  983.     clc
  984.     ret
  985.  
  986. code    ends
  987.  
  988.     end
  989.